
#include <stdio.h>
#include <stdlib.h>

typedef struct gmiCmpHdr_s
{
	unsigned char			id[4]; //"CMPS"
	int				cmpType;
	int				decompSize;
	int				resv;
} gmiCmpHdr_t;

//decompress data
static unsigned char *descomprime(unsigned char *src, int leng)
{
	gmiCmpHdr_t *cmpHdr = (gmiCmpHdr_t *)src;
	int srcLen = leng;
	int dstLen = cmpHdr->decompSize;
	unsigned char* dst = (unsigned char*)malloc(dstLen);
	int srcPtr = sizeof(gmiCmpHdr_t);
	int dstPtr = 0;

	while (srcPtr < srcLen && dstPtr < dstLen)
	{
		unsigned char ctrl = src[srcPtr++];
		for (int i = 0; i < 8 && srcPtr < srcLen && dstPtr < dstLen; i++)
		{
			if (ctrl & (1<<i))
			{ //literal
				dst[dstPtr++] = src[srcPtr++];
			}
			else
			{ //ofs+len
				unsigned short int ol = *(unsigned short int *)(src+srcPtr);
				srcPtr += sizeof(unsigned short int);
				int len = 3 + ((ol>>8) & 15);
				int relOfs = (ol & 255) | ((ol>>12) << 8);
				int ofs = dstPtr - ((dstPtr-18-relOfs) & 4095);
				for (int j = 0; j < len && dstPtr < dstLen; j++)
				{
					if (ofs+j < 0 || ofs+j >= dstPtr)
					{
						dst[dstPtr++] = 0;
					}
					else
					{
						dst[dstPtr++] = dst[ofs+j];
					}
				}
			}
		}
	}
	if(srcPtr > srcLen) {
        exit(1);      
    }
	if(dstPtr > dstLen) {
        exit(1);
    }

	leng = dstLen;

	FILE* saida = fopen("saida.tpl", "wb");
	fwrite(dst, 1, dstLen, saida);
	fflush(saida);
	fclose(saida);

	return dst;
}

int main() {
    
    FILE* fentrada = fopen("1930_vs00a_jp.tpl", "rb");
    if (fentrada==NULL) {
        exit(1);               
    }
    
    unsigned char* entrada = (unsigned char*)malloc(27424);
    fread(entrada, 1, 27424, fentrada);
    
    descomprime(entrada, 27424);

   return 0;
}
